在前幾天認識了 Promise 後,還有其他作非同步處理的方式,所以這篇來介紹一下 async/await。
async/await 為 Generator + Promise 的語法糖,這個語法可以讓開發者撰寫看起來像同步的非同步程式碼,async 會加在函式前面,該函式被呼叫後會返回一個 Promise 物件。
並且如果該函式回傳了一個值,Promise 的狀態將為一個帶有該回傳值的 resolved/fulfilled。如果該函式拋出例外或某個值,Promise 的狀態將為一個帶有被拋出值的 rejected。
可以看以下截圖運行結果,exampleFunc 回傳了一個值 hi,所以是 resolved/fulfilled 狀態:
而 await 要在加上 async 的函式內執行,它會暫停此 async 函式的執行,從程式執行面看的話:
這樣說可能蠻抽象,所以讀者可以將這三個步驟搭配下面的範例程式觀看。
直接從程式看的話,這兩個範例執行結果是一樣的:
async function asyncExampleFunc1() {
console.log('Hi, I will run first.');
await asyncExampleFunc2();
console.log('I need to wait...Orz');
}
async function asyncExampleFunc2() {
console.log('I will run just like synchronously.');
}
asyncExampleFunc1();
console.log('I need to wait...Orz'); 可以當作 microtask,就如同 Promise.then()。
async function asyncExampleFunc1() {
console.log('Hi, I will run first.');
Promise.resolve(asyncExampleFunc2()).then(() => {
console.log('I need to wait...Orz');
})
}
async function asyncExampleFunc2() {
console.log('I will run just like synchronously.');
}
asyncExampleFunc1();
從語法糖的角度看,await 就相當於 Promise 的 then,await 後面的程式碼會當作 Microtasks 存放到 Job Queue,而 try catch 語法則代替了 Promise 的 catch 做錯誤處理。
接下來我們來看更多範例,讓自己更了解 async/await。
async await 常見搭配 try catch 語法去做錯誤處理
const getPosts = async () => {
try {
const posts = await getPostsApi(...);
console.log(posts);
} catch(err) {
console.log(err);
}
};
function returnPromise(time) {
return new Promise((resolve) => {
setTimeout(() => resolve(time), Math.random() * 5000);
})
}
const randomTime = Math.floor(Math.random() * 5);
async function returnThreePromise() {
try {
const promise1value = await returnPromise(randomTime);
console.log('myPromise1 resolve:', promise1value);
const promise2value = await returnPromise(2);
console.log('myPromise2 resolve:', promise2value);
const promise3value = await returnPromise(3);
console.log('myPromise3 resolve:', promise3value);
} catch(error) {
console.log(error);
}
}
returnThreePromise();
前面是使用 Promise 去處理 Promise.all()/Promise.race() 回傳的 Promise 物件,這次改寫用 async/await 處理:
function getPromise(i) {
return new Promise((resolve) => {
setTimeout(() => resolve(i), Math.random() * 5000);
})
}
const arr = [];
for (let i = 0; i < 5; i++) {
arr.push(getPromise(i));
}
// 多個同時執行,所有 promise 被處理才被回傳
async function parallel() {
const result = await Promise.all(arr);
console.log(result); // [0, 1, 2, 3, 4]
}
// 最先完成的才被回傳
async function race() {
const result = await Promise.race(arr);
console.log(result); // 印出 0~4 其中一個數字
}
parallel();
race();
這題目是從 Day19 的題目延伸而來,現在我們瞭解了 Promise & async/await,可以來小試身手一下!
async function asyncExampleFunc1() {
console.log('Hi, I will run first.');
await asyncExampleFunc2();
console.log('I need to wait...Orz');
}
async function asyncExampleFunc2() {
console.log('I will run just like synchronously.');
}
setTimeout(() => {
console.log('I will be printed out first.');
}, 0);
asyncExampleFunc1();
const promiseExample = new Promise(function (resolve) {
console.log('Promise executor function will run synchronously');
resolve('But I still faster than you, Mr.SetTimeout. I am a microtask.')
}).then((data) => {
console.log(data);
})
function mockFunc() {
console.log('Shut up! I am a synchronous task so I will run first.');
}
mockFunc();
讀者也可以進去此 Codepen 查看執行結果
如果 Day4 & 上篇文章和這篇文章都有讀完並了解的話,這題我想可以解的出來,若還不熟悉可以再重新閱讀一下!
Promise 和 async/await 就介紹到這邊啦~下一篇會將也可以做非同步處理但還沒有介紹到的 Generator 產生器做介紹。
問底下程式碼的 console.log 印出什麼? 解答在留言區。
async function getData() {
return await Promise.resolve('I made it!');
}
const data = getData();
console.log(data);
[JS] Async and Await in JavaScript
一篇文章解决Promise...then,async/await执行顺序类型题
印出 Promise {<pending>}
,async 函式會回傳一個 Promise 物件,而 await 會等待 Promise 進到 resolve 狀態,所以是 pending 狀態。